#!/usr/local/bin/ruby -rubygems
$:.unshift File.dirname(__FILE__) + "/../../lib"
%w(rubygems redcloth camping active_record).each { |lib| require lib } 
require 'camping'
require 'camping/session'
require 'action_view/helpers/date_helper.rb'
Camping.goes :Goodies

module Goodies
        include Camping::Session
        include ActionView::Helpers::DateHelper
end

##################### MODELS

module Goodies::Models
  
 class Link < Base
  belongs_to :user
 end
 
 class User < Base; end

 class CreateTheBasics < V 1.0
  
  def self.up
   
   create_table :goodies_links, :force => true do |t|
    t.column :id, :integer, :null => false
    t.column :user_id, :integer, :null => false
    t.column :title, :string, :limit => 255
    t.column :address, :string, :limit => 255
    t.column :created_at, :datetime
    t.column :updated_at, :datetime
    t.column :description, :text
    t.column :alternative_links, :text #links to projects or other goodies that do the same thing as this goodie
    t.column :applicable_to_version, :string
    t.column :link_type, :string, :limit => 255 #ie, "Framework", "Walk Through", ""
    # some extra things
    t.column :primary_language, :string, :default => "Objective-C"
    t.column :author,                :string
    t.column :authors_email,         :string
    t.column :authors_webpage,      :string
    t.column :authors_skype,         :string
    t.column :authors_ichat,         :string
    t.column :direct_download_link, :string #a link to a downloadable file for this entry (for example if there are lots of goodies on the one page we would like to have a single link for each)
    t.column :screenshot_link, :string #something to display inline in the entry so you can see what it's going to look like
    t.column :actual_code, :text    # a place for people to post snippets of code, in the form of plain text, right here on the site. 
   end
   
   Link.reset_column_information
   
   create_table :goodies_users, :force => true do |t|
    t.column :id, :integer, :null => false
    t.column :username, :string
    t.column :password, :string
    t.column :email, :string 
    t.column :webpage, :string 
    t.column :skype, :string
    t.column :ichat, :string
    t.column :description, :text
    t.column :reveal_contacts, :boolean
   end
   
  end
  
  def self.down
   drop_table  :goodies_links
   drop_table  :goodies_users
  end
 end
end

##################### CONTROLLERS
module Goodies::Controllers
  
        class Tag < R '/tag/(\s+)', '/tag', '/tags/(\s+)'
          #takes a string of tags joined with + and finds all the tags in the database with these tags
           def get
             #generate the tag list
             @all_links = Link.find :all
             @taglist = []
             @all_links.each do |link|
              link.link_type.split(" ").each do |tag|
                  @taglist << tag
              end
             end
             @taglist.uniq!
             @taglist.sort!
             
             # add this snippet into any method that the user details want to be viewed.
             unless @state.user_id.blank?
              @user = User.find @state.user_id
             end
             #now which tags are we asked for?
             tagstring = @input[:tags].to_s
             @tags_to_show = tagstring.split("+")
             @refinedlinks = []
             @all_links.each do |link|
                this_links_tags = link.link_type.split(" ")
                 this_links_tags.each do |link_tag|
                   @tags_to_show.each do |atag|
                    if link_tag.eql?(atag)
                      @refinedlinks << link
                    end
                   end
                 end
             end
             @refinedlinks.uniq!
             render :tags
           end
        end
        
        class Index < R '/'
         def get
           @all_links = Link.find :all
           @taglist = []
           @all_links.each do |link|
            link.link_type.split(" ").each do |tag|
              @taglist << tag
            end
           end
           @taglist.uniq!
           @taglist.sort!
          unless @state.user_id.blank?
           @user = User.find @state.user_id
           @links = Link.find(:all, :conditions => {:user_id => @state.user_id})
          end
          render :index
         end
        end

        class Add
         def get
           @taglist = nil
           
          unless @state.user_id.blank?
           @user = User.find @state.user_id
           @link = Link.new :title => input.link_title,
            :address => input.address,
            :description => input.description,
            :link_type => input.link_type,
            :primary_language => input.primary_language,
            :authors_email => input.authors_email,
            :applicable_to_version => input.applicable_to_version,
            :alternative_links => input.alternative_links,
            :direct_download_link => input.direct_download_link,
            :screenshot_link => input.screenshot_link,
            :actual_code => input.actual_code,
            :user_id => @state.user_id
          end
          render :add
         end
        
         def post
          unless @state.user_id.blank?
           link = Link.create :title => input.link_title,
           :address => input.address,
           :description => input.description,
           :link_type => input.link_type,
           :primary_language => input.primary_language,
           :authors_email => input.authors_email,
           :applicable_to_version => input.applicable_to_version,
           :alternative_links => input.alternative_links,
           :direct_download_link => input.direct_download_link,
           :screenshot_link => input.screenshot_link,
           :actual_code => input.actual_code,           
           :user_id => @state.user_id
           redirect Index
          end
         end
        end
        
        class Show < R '/show/(\d+)', '/show'
          def get link_id
            #generate the tag list
            @all_links = Link.find :all
            @taglist = []
            @all_links.each do |link|
             link.link_type.split(" ").each do |tag|
                 @taglist << tag
             end
            end
            @taglist.uniq!
            @taglist.sort!
            
            unless @state.user_id.blank?
              @user = User.find @state.user_id
            end
            @taglist = nil
            @link = Link.find link_id
            render :show
          end
        end

        class View < R '/view/(\d+)', '/view'
         def get link_id
           @taglist = nil
          unless @state.user_id.blank?
             @user = User.find @state.user_id
          end
          @link = Link.find link_id
          render :view
         end
         
         def post
          unless @state.user_id.blank?
           @link = Link.find input.link_id
           @link.update_attributes :title => input.link_title,
           :address => input.address,
           :description => input.description,
           :link_type => input.link_type,
           :primary_language => input.primary_language,
           :authors_email => input.authors_email,
           :applicable_to_version => input.applicable_to_version,
           :alternative_links => input.alternative_links,
           :direct_download_link => input.direct_download_link,
           :screenshot_link => input.screenshot_link,
           :actual_code => input.actual_code,
           :description => input.description
           redirect Index
          end
         end
        end

        class Delete < R '/delete/(\d+)', '/delete'
           def get link_id
             @taglist = nil

            unless @state.user_id.blank?
             @user = User.find @state.user_id
             @link = Link.find link_id
             render :delete
            end
           end
           def post
            unless @state.user_id.blank?
                     Link.delete(input.link_id)
                     redirect Index
            else
             redirect Index
            end
           end
        end

        class Login
          
        def get
          redirect Index
        end
        
         def post
          @user = User.find :first, :conditions => ['username = ? AND password = ?', input.username, input.password]
          @taglist = nil

          if @user
               @login = 'login success !'
               @state.user_id = @user.id
          else
           if input.user_add and not
                input.password.empty? and not
                 input.username.empty?
            @user = User.create :username =>
              input.username,
             :password => input.password
            @login = 'Account successfully created!'
           else
            @login = 'Wrong user name or password!'
           end
          end
          render :login
         end
        end

        class Logout
         def get
           @taglist = nil
           
          @state.user_id = nil
          render :logout
         end
        end
        
        class All < R '/all'
          
            def get
              @all_links = Link.find :all
              @taglist = []
               @all_links.each do |link|
                link.link_type.split(" ").each do |tag|
                    @taglist << tag
                end
               end
               @taglist.uniq!
               @taglist.sort!

             unless @state.user_id.blank?
                @user = User.find @state.user_id
             end
            page = @input.page.to_i
             if page > 0
                 page -= 1
             end
                 @links = Link.find :all, :offset => page * 20, :limit => 20
                 render :all
            end
        end
        
        class Style < R '/styles.css'
          def get
            
          @headers['Content-Type'] = 'text/css'
          File.read('styles.css')
          end
        end
end

##################### VIEWS
module Goodies::Views
   
  # formats textilized string and returns html
	def red(str)
		require 'redcloth'
		self << RedCloth.new( str ).to_html
	end
	
	 def self.to_code(io)
	 require 'bluecloth'
	   code = String.new
	   LRB.new.parse(io) do |type, line|
	 code << line if type == :code
   end
   return code
 end
  
  def layout
    html do
     head do
      title 'Goodies'
      link :href=>R(Style), :rel=>'stylesheet', :type=>'text/css' 
     end
     body do
       div.personalDetails do
      if @user
       p do
        [('Hi '+@user.username+''), a('+ Goodie', :href => R(Add)), a('My Goodies', :href => R(Index)),
                a('Everyones Goodies', :href => R(All)), a('Logout', :href => R(Logout))].join("  |  ") 
       end
      else
        a 'Login', :href => R(Login) 
      end
      
    end
      
      h1.h { a.h 'Goodies.', :href => R(Index)}
      #the tags list will be on the left hand side of the screen
      div.mainContent do
        div do
          if(taglist)
            #div.taglistitem
            div.tagcolumn do
              div.tagtitle do 'Tags' end
              div {a 'All', :href => R(All)} #a special one to view all
                taglist.each do |tag|
                  div {a tag, :href => '/tag/?tags='+tag+''}
                end
            end #td
          end #if
          div.righthandside do
             self << yield 
          end
        end #table
      end #mainContent
     end #body
    end #html
  end #layout
   
   def tags
        if @refinedlinks.empty?
         p 'Nothing were no goodies found with the tags(s) "'+tags_to_show.to_s+'"';
         p {a 'Add a new link now!', :href => R(Add)} 
        else
        p "Goodies with tags \'"+tags_to_show.to_s+"\'"  
         p ''+@refinedlinks.size.to_s+' found!'
         for link in @refinedlinks
          _entry(link)
         end
        end
   end
   
   def index
    if @user
     h1 "Your Goodies"
     if @links.empty?
      p {a 'Add a link now!', :href => R(Add)} 
      p 'You don\'t have any goodies saved';
     else
      p {a 'Add a link now!', :href => R(Add)}
      div.righthandside do
        for link in @links.reverse
         _listentry(link)
        end
      end
     end
    else
    _welcomeMessage
     a 'Browse All Goodies', :href => R(All)
     h1 "Please login"
     _login
     p 'You can just ' 
     a 'browse', :href => R(All) 
     p' without logging in'
    end
   end
   
   def all
     p 'Viewing All'
     if @links
       for link in @links
       _listentry(link)
       end
     end
   end

   def login
    p {b @login}
    p {a 'Continue', :href => R(Index)}
   end

   def logout
    p 'You have been logged out'
    p {a 'Continue', :href => R(Index)}
   end

   def add
    if @user
     _form(@link, :action => R(Add))
    else
     _login
    end
   end

   def delete
    p "Are you sure that you want to delete the link to the goodie \'"+@link.title+"\'?"
    br
    form :action => R(Delete), :method => 'post' do
     input :type => 'hidden',
      :name => 'link_id', :value => @link.id 
     input :type => 'submit',
      :name => 'delete', :value => 'Delete'
    end
   end

   def view
    if @user
     _form(@link, :action => R(View))
    else
     _login
    end
   end
   
   def show
     _fullentry(@link)
   end
   
   ################### Partials
   
   def _login
    form :action => R(Login), :method => 'post' do
      #the fields:
      label 'Username', :for => 'username'; br
      input :name => 'username', :type => 'text'; br
      label 'Password', :for => 'password'; br  
      input :name => 'password', :type => 'text'; br
      
      #the buttons and their actions:
      input :type => 'submit', :name => 'login', :value => 'Login'
##      input :type => 'submit', :name => 'user_add', :value => 'Create Account' //we don't allow signups yet
    end
   end
   
   def _welcomeMessage
     p("A welcome message")
   end
   
   def _controls(link)
     if (link.direct_download_link.length > 0)
      [a.nav('Show', :href => R(Show, link.id)), a.downloadLink('Download', :href => link.direct_download_link)].join("  |  ")
     else
      [a.nav('Show', :href => R(Show, link.id))].join("  |  ")
     end
   end
   
    def _listentry(link)
        h2 {a.h link.title, :href => link.address}
     p do
       _controls(link)
     end
    end

    def _fullentry(link)
      div.entry do
        h2 {a.h link.title, :href => link.address}

        if link.screenshot_link
          div.screenshot do
            img.screenshot :src => link.screenshot_link, :border => '1'
          end
        end
        div.linkcontent do
         p.linkdescription link.description
         p.taglist 'tags - ' +link.link_type+ ''
         br
         if (link.actual_code)
           p.code do
      			 link.actual_code.to_s
           end
         end
        end
         (p.date 'Added on '+ link.created_at.strftime("%d. %B %Y") + ' by '+@user.username)
       p do
         _controls(link)
       end
       br
         if (@user.id == link.user.id)
           a.nav('Delete', :href => R(Delete, link.id))
           a.nav('Edit', :href => R(View, link.id))
         end
      end
    end

   def _entry(link)
     div.entry do
       h2 {a.h link.title, :href => link.address}
       
       if link.screenshot_link
         div.screenshot do
           img.screenshot :src => link.screenshot_link, :border => '1'
         end
       end
       div.linkcontent do
        p.linkdescription link.description
        p.taglist 'tags - ' +link.link_type+ ''
        br
        if (link.actual_code)
          p.code do
             link.actual_code.to_s
          end
        end
       end
        (p.date 'Added: '+ link.created_at.strftime("%d. %B %Y"))
      p do
        _controls(link)
      end
     end
   end

   def _form(link, opts)
    form({:method => 'post'}.merge(opts)) do
      
      i 'Change the item\'s details'; br 
      br
      div.formArea do
		  #fields:
		  label 'Title', :for => 'link_title'; br
		  input :name => 'link_title', :type => 'text', :value => link.title; br
	
		  label 'Link URL', :for => 'link_address'; br
		  textarea link.address, :name => 'address'; br
	
		  label 'Description', :for => 'description'; br
		  textarea link.description, :name => 'description'; br
		  
		  label 'Tags - ie, NSBox category Framework subclass.', :for => 'link_type'; br
		  input :name => 'link_type', :type => 'text', :value => link.link_type; br
		  
		  label 'Primary Language - ie Objective-C or English', :for => 'primary_language'; br
		  input :name => 'primary_language', :type => 'text', :value => link.primary_language; br
		  
		  label 'Applicable to Version - ie OS X 10.4 or Rails 1.2', :for => 'applicable_to_version'; br
		  input :name => 'applicable_to_version', :type => 'text', :value => link.applicable_to_version; br
	
		  label 'Direct Download Link', :for => 'direct_download_link'; br
		  input :name => 'direct_download_link', :type => 'text', :value => link.direct_download_link; br
	
		  label 'Screenshot', :for => 'screenshot_link'; br
		  input :name => 'screenshot_link', :type => 'text', :value => link.screenshot_link; br      
		  
		  label 'Actual Code / or snippet', :for => 'actual_code'; br
		  textarea link.actual_code, :name => 'actual_code'; br
		  
		  label 'Alternatives, or "Links (comma separated, please) to other sites / goodies that do the same thing"', :for => 'alternative_links'; br
		  textarea link.alternative_links, :name => 'alternative_links'; br
      end

      #fields: buttons
      input :type => 'hidden',
        :name => 'link_id', :value => link.id
      input :type => 'submit', :value => 'Done!'
    end
   end
end

def Goodies.create
  Goodies::Models::Base.establish_connection(
   :adapter => 'sqlite3',
   :database => 'goodies.db')
    Camping::Models::Session.create_schema
    Goodies::Models.create_schema :assume =>
(Goodies::Models::Link.table_exists? ? 1.0 : 0.0)
end
